package com.lvhr.rpc.server.tcp;

import com.lvhr.rpc.RpcApplication;
import com.lvhr.rpc.filter.*;
import com.lvhr.rpc.filter.SecurityException;
import com.lvhr.rpc.model.*;
import com.lvhr.rpc.protocol.*;
import com.lvhr.rpc.registry.LocalRegistry;
import io.vertx.core.Handler;
import io.vertx.core.net.NetSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * TCP服务端请求处理器
 * 职责：
 * 1. 接收客户端请求并解码
 * 2. 执行安全校验
 * 3. 反射调用目标服务
 * 4. 返回响应结果
 */
public class TcpServerHandler implements Handler<NetSocket> {
    private static final Logger logger = LoggerFactory.getLogger(TcpServerHandler.class);

    // 安全校验链（包含token验证和时间戳验证）
    private final SecurityValidationChain securityChain = new SecurityValidationChain()
            .addValidator(new TokenValidator(RpcApplication.getRpcConfig().getSecurityConfig().getToken()))
            .addValidator(new TimestampValidator(5000))
            .addValidator(new TimestampValidator(3000)) // 3秒窗口
            .addValidator(new NonceValidator());// 防重放
    private final SecurityValidationChain securityChainEnable = new SecurityValidationChain()
            .addValidator(new TokenValidator(RpcApplication.getRpcConfig().getSecurityConfig().getToken()))
            .addValidator(new TimestampValidator(5000))
            .addValidator(new TimestampValidator(3000)) // 3秒窗口
            .addValidator(new NonceValidator())        // 防重放
            .addValidator(new SignatureValidator(RpcApplication.getRpcConfig().getSecurityConfig().getSecretKey()));

    /**
     * 处理客户端连接的主入口方法
     * @param socket 客户端网络套接字
     */
    @Override
    public void handle(NetSocket socket) {
        // 使用自定义的缓冲区处理器包装器处理TCP粘包/拆包
        TcpBufferHandlerWrapper bufferHandlerWrapper = new TcpBufferHandlerWrapper(buffer -> {
            try {
                // 1. 协议解码（将字节流转换为协议消息对象）
                ProtocolMessage<RpcRequest> protocolMessage =
                        (ProtocolMessage<RpcRequest>) ProtocolMessageDecoder.decode(buffer);

                // 2. 安全校验（验证token和时间戳）
                if (! RpcApplication.getRpcConfig().getSecurityConfig().isEnableSignature()){
                    if (!securityChain.validate(protocolMessage.getBody())) {
                        sendErrorResponse(socket, 403, "安全校验不通过");
                        return;
                    }
                }
                if (RpcApplication.getRpcConfig().getSecurityConfig().isEnableSignature()){
                    if (!securityChainEnable.validate(protocolMessage.getBody())) {
                        sendErrorResponse(socket, 403, "安全校验不通过");
                        return;
                    }
                }

                // 3. 处理业务请求
                processRequest(socket, protocolMessage);
            } catch (IOException e) {
                logger.error("协议解码失败", e);
                sendErrorResponse(socket, 400, "协议格式错误");
            } catch (SecurityException e) {
                logger.warn("安全校验异常", e);
                sendErrorResponse(socket, 403, e.getMessage());
            }
        });

        // 注册处理器到socket
        socket.handler(bufferHandlerWrapper);
    }

    /**
     * 处理RPC业务请求核心方法
     * @param socket 客户端连接套接字（用于返回响应）
     * @param protocolMessage 包含请求信息的协议消息
     */
    private void processRequest(NetSocket socket, ProtocolMessage<RpcRequest> protocolMessage) {
        RpcRequest rpcRequest = protocolMessage.getBody();
        RpcResponse rpcResponse = new RpcResponse();

        try {
            // 1. 从本地注册中心获取服务实现类
            Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName());

            // 2. 通过反射获取目标方法
            Method method = implClass.getMethod(
                    rpcRequest.getMethodName(),
                    rpcRequest.getParameterTypes()
            );

            // 3. 反射调用方法（创建新实例并执行）
            Object result = method.invoke(
                    implClass.getDeclaredConstructor().newInstance(),
                    rpcRequest.getArgs()
            );

            // 4. 构造成功响应
            rpcResponse.setData(result);
            rpcResponse.setDataType(method.getReturnType());
            rpcResponse.setAttachments(rpcRequest.getAttachments());
            rpcResponse.setMessage("ok");

            // 5. 发送响应
            sendSuccessResponse(socket, protocolMessage.getHeader(), rpcResponse);
        } catch (NoSuchMethodException e) {
            handleServiceError(socket, 404, "方法不存在: " + rpcRequest.getMethodName(), e);
        } catch (InvocationTargetException e) {
            handleServiceError(socket, 500, "服务执行异常", e.getTargetException());
        } catch (Exception e) {
            handleServiceError(socket, 500, "服务调用异常", e);
        }
    }

    /**
     * 发送成功响应
     * @param socket 目标套接字
     * @param header 原始协议头（复用消息ID等字段）
     * @param response 业务响应数据
     */
    private void sendSuccessResponse(NetSocket socket,
                                     ProtocolMessage.Header header,
                                     RpcResponse response) {
        try {
            // 1. 设置响应类型和状态
            header.setType((byte) ProtocolMessageTypeEnum.RESPONSE.getKey());
            header.setStatus((byte) ProtocolMessageStatusEnum.OK.getValue());

            // 2. 构造协议消息并编码发送
            ProtocolMessage<RpcResponse> responseMessage =
                    new ProtocolMessage<>(header, response);
            socket.write(ProtocolMessageEncoder.encode(responseMessage));
        } catch (IOException e) {
            logger.error("响应编码失败", e);
        }
    }

    /**
     * 发送错误响应（简化版）
     * @param socket 目标套接字
     * @param statusCode HTTP状态码
     * @param message 错误信息
     */
    private void sendErrorResponse(NetSocket socket, int statusCode, String message) {
        sendErrorResponse(socket, RpcResponse.fail(statusCode, message));
    }

    /**
     * 发送错误响应（完整版）
     * @param socket 目标套接字
     * @param errorResponse 预构建的错误响应对象
     */
    private void sendErrorResponse(NetSocket socket, RpcResponse errorResponse) {
        try {
            ProtocolMessage.Header header = new ProtocolMessage.Header();
            header.setType((byte) ProtocolMessageTypeEnum.RESPONSE.getKey());
            header.setStatus((byte) ProtocolMessageStatusEnum.BAD_REQUEST.getValue());

            ProtocolMessage<RpcResponse> responseMessage =
                    new ProtocolMessage<>(header, errorResponse);
            socket.write(ProtocolMessageEncoder.encode(responseMessage));
        } catch (IOException e) {
            logger.error("错误响应编码失败", e);
        }
    }

    /**
     * 统一处理服务异常
     * @param socket 目标套接字
     * @param statusCode 状态码
     * @param message 错误信息
     * @param cause 异常对象
     */
    private void handleServiceError(NetSocket socket,
                                    int statusCode,
                                    String message,
                                    Throwable cause) {
        logger.error(message, cause);
        RpcResponse errorResponse = RpcResponse.fail(statusCode, message);
        errorResponse.setException((Exception) cause);
        sendErrorResponse(socket, errorResponse);
    }

}
